﻿/*
   Open Intel 
   Copyright © 2011 – ISC. All Rights Reserved.
*/

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Caliburn.Micro;
using ISC.RIM.Silverlight;
using OI.Async;
using OI.Controls;
using OI.Events;
using OI.Framework;
using System.Windows.Data;

namespace OI.ViewModels
{
    [Export("MashupLegendViewModel", typeof(MashupLegendViewModel))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class MashupLegendViewModel : Screen, 
        IHandle<SelectMap>, 
        IHandle<DisplayRIMMap>, 
        IHandle<ChangeMapScale>,
        IHandle<ClearSelectedLayer>
    {
        #region DATA
        readonly IEventAggregator Events;
        public ISC.MapDotNetServer.Common.Maps.Map Map { get; private set; }
        public Map RIMMap { get; private set; }
        public TileLayer MDNTileLayer { get; private set; }
        
        // legend items
        public BindableCollection<LegendItem> Items
        {
            get { return _Items ?? (_Items = new BindableCollection<LegendItem>()); }
        }
        private BindableCollection<LegendItem> _Items;
        #endregion


        [ImportingConstructor]
        public MashupLegendViewModel(IEventAggregator events)
		{
            Events = events;
			events.Subscribe(this);
		}


        // handle when a RIM Map is ready
        public void Handle(DisplayRIMMap message)
        {
            RIMMap = message.Map;
            MDNTileLayer = message.MDNTileLayer;
        }


        // when a new map is launched, the legend is notified
        // we will setup the legend items here
        public void Handle(SelectMap message)
        {
            Map = message.Map;

            Items.Clear();

            // remember, layers in a legend start from the bottom up (first item in legend is last item in layer list)

            for (int idx = Map.Layers.Count - 1; idx >= 0; idx--)
            {
                var layer = Map.Layers[idx];
                var item = new LegendItem(layer, IconProvider, Events);
                Items.Add(item);
            }
        }


        // scale changes from the map are handled here
        public void Handle(ChangeMapScale message)
        {
            Items.Apply(i => i.CurrentScale = message.Scale);
        }


        // handles the clear selected layer event
        public void Handle(ClearSelectedLayer message)
        {
            Items.Apply(i => i.IsSelected = false);
        }



        // provides a BitmapImage for the legend icon
        public BitmapImage IconProvider(string layerID, string classID, double scale, int size)
        {
            var icon = new BitmapImage();
             Coroutine.BeginExecute(GetLegendIcon(layerID, classID, scale, size, icon));
            return icon;
        }


        // synch'd asynch call to get legend icon source stream
        public IEnumerator<IResult> GetLegendIcon(string layerID, string classID, double scale, int size, BitmapImage icon)
        {
            var gli = new MDNGetLegendIcon(Map, layerID, classID, scale, size);
            yield return gli;

            if (gli.Results != null)
            {
                icon.SetSource(gli.Results);
            }
        }

        public void MoveLayerUp(LegendItem item)
        {
            int idx = Items.IndexOf(item);
            if (idx > 0)
            {
                Items.Remove(item);
                Items.Insert(idx - 1, item);

                // notify map of change
                Events.Publish(new MapLayerUpInList
                {
                    Layer = item.Layer
                });
            }
        }


        public void MoveLayerDown(LegendItem item)
        {
            int idx = Items.IndexOf(item);
            if (idx > -1 && idx < Items.Count - 1)
            {
                Items.Remove(item);
                Items.Insert(idx + 1, item);

                // notify map of change
                Events.Publish(new MapLayerDownInList
                {
                    Layer = item.Layer
                });
            }
        }


        public void RemoveLayer(LegendItem item)
        {
            Items.Remove(item);

            // publish event
            Events.Publish(new MapLayerRemoveFromList
            {
                Layer = item.Layer
            });
        }


        // update the data context on sub classes
        public void SubclassLoaded(ItemsControl ctrl, LegendItem item)
        {
            ctrl.DataContext = item;
            item.IsSubclassExpanded = item.InRange && item.Classes.Count > 1;
        }


        // add any filters or density mapping to the right-click menu
        public void ItemMenuLoaded(ContextMenu menu, LegendItem item)
        {
            // if we have already loaded or there is nothing to load
            if (menu.Items.Count > 4)
            {
                return;
            }

            // filter support
            if (item.HasActiveFilters)
            {
                // add separator
                var sep = new Separator();
                menu.Items.Add(sep);

                BindMenuItemToLayerItemVisibility(sep, item);

                // add filter items to the context menu
                foreach (var f in item.Filters)
                {
                    var newMenuItem = new System.Windows.Controls.MenuItem();

                    BindMenuItemToLayerItemVisibility(newMenuItem, item);

                    // icon
                    var filterIcon = new FilterIcon
                    {
                        HorizontalAlignment = HorizontalAlignment.Center
                    };
                    newMenuItem.Icon = filterIcon;

                    // header
                    var header = new TextBlock
                    {
                        Style = Application.Current.Resources["MenuItems"] as Style,
                        Text = f.Name
                    };

                    // click handler
                    var filter = f;
                    newMenuItem.Click += (s, e) =>
                    {
                        filter.IsEnabled = true;
                        FilterItem.XorFilter(item.Filters, filter);
                        item.FilterChange();
                    };

                    newMenuItem.Header = header;
                    menu.Items.Add(newMenuItem);
                }
            }

            // density mapping support
            if (item.HasDensityMapSupport)
            {
                // add separator
                var sep = new Separator();
                menu.Items.Add(sep);

                var newMenuItem = new System.Windows.Controls.MenuItem();

                BindMenuItemToLayerItemVisibility(newMenuItem, item);

                // icon
                var dmIcon = new DensityMapIcon
                {
                    HorizontalAlignment = HorizontalAlignment.Center
                };
                newMenuItem.Icon = dmIcon;

                // header
                var header = new TextBlock
                {
                    Style = Application.Current.Resources["MenuItems"] as Style,
                    Text = "Toggle Density Mapping"
                };

                // click handler
                newMenuItem.Click += (s, e) =>
                {
                    bool newState = !item.IsDensityMapVisible;

                    // if we are enabling an item, go through and turn off any other layer with DM enabled
                    // only one can be on at a time since we load a single MDNGeomTileLayer
                    Items.Apply(i => { if (i != item) i.IsDensityMapVisible = false; });

                    item.IsDensityMapVisible = newState;
                };

                newMenuItem.Header = header;
                menu.Items.Add(newMenuItem);
            }
        }

        private void BindMenuItemToLayerItemVisibility(System.Windows.Controls.Control menuItem, LegendItem legendItem)
        {
            Binding binding = new Binding("IsVisible");
            binding.Source = legendItem;
            binding.Mode = BindingMode.OneWay;
            binding.Converter = new BoolToVisibilityConverter();
            menuItem.SetBinding(System.Windows.Controls.MenuItem.VisibilityProperty, binding);
        }
    }
}
